/*
 *  FSMState.cpp
 *  tractionedge
 *
 *  Created by Steven Hamilton on 28/09/10.
 *  Copyright 2010 n/a. All rights reserved.
 *
 */

#include "FSMState.h"
#include "Logger.h"
#include "Utility.h"

AIStatePatrol::AIStatePatrol()
{
	type=AI_STATE_PATROL;
}

void AIStatePatrol::enter(Creature* creature)
{
    Utility tool;
	LOG(creature->objectId,"Entering Patrol State");
	//choose a location to move to.
	//must be reachable, within distance, non-blocked.
    //firstly just pick a random spot within 10 blocks.
    //store a movelist to get there. 
	do {
        point=creature->aiFindPatrolPoint();
        moves=tool.findPath(creature->position, point);
    } while (moves.size() == 0);
    movesIter = moves.end();
    LOG(creature->objectId, " at "+creature->position.string()+" is patrolling to "+point.string());
}

void AIStatePatrol::update(Creature* creature)
{
    //Patrol State will pick a suitable patrol point and move towards it.
	Utility tool;
    LOG(creature->objectId,"Updating Patrol State");
    

    //update awareness
    creature->processFOV();

    //if we can see an enemy change assess whether we should run or attack
    if (creature->visibleEnemies.size()>0){
        //first look for a safe spot to run to and get the cost of that move.
        //If we can attack and still reach safety then do so. If not, just run
        //for it.
        Position safety=creature->aiFindSafety();
        LOG(creature->objectId,"safety: "+safety.string());        
        int safetyMoveCost=tool.costForMove(creature->position, safety);
        WORLD.setFiringMode(SNAPSHOT);
        if (creature->hasActionPoints(WORLD.firingCost+safetyMoveCost)){
            creature->aiFSM.changeState(creature, AI_STATE_ATTACK);
        } else {
            creature->destination = safety;
            creature->aiFSM.changeState(creature, AI_STATE_RUN);
        }
        return;
    }
    //pick a new destination if we have reached patrol point.
    if (creature->position==point){
        do {
            point=creature->aiFindPatrolPoint();
            moves=tool.findPath(creature->position, point);
        } while (moves.size() == 0);
        movesIter = moves.end();
		LOG(creature->objectId,"Reached patrolPoint, now point is "+point.string());
    }
    //check we have enough AP for the next move and move towards patrol point
    movesIter--;
    Position nextPosition=tool.getPositionFromDirection(creature->position, (*movesIter));
	int moveCost=WORLD.map.getMoveCost(nextPosition);
    if (creature->hasActionPoints(moveCost))
    {

		LOG(creature->objectId,"at position "+creature->position.string()+" with AP "+tool.stringFromInt(creature->currentActionPoints)
			+" target is "+point.string());
		//if we can't move for whatever reason end the creatures turn. Probably got stuck somewhere.
        //movesIter--;
        bool moved=creature->move((*movesIter));
		if (!moved) {
			creature->endTurn=true;
		}
        LOG(creature->objectId,"moving in direction "+tool.stringFromInt(*movesIter)+" Position is now "+creature->position.string());
    } else {
        //No AP's so end turn. Ensure we increment the movesIter so we pick up
        //the correct move on the next turn.
        movesIter++;
        creature->endTurn=true;
        LOG(creature->objectId,"No ActionPoints: ending turn");
    }
}

void AIStatePatrol::exit(Creature* creature)
{
	LOG(creature->objectId,"Exiting Patrol State");
}

//------
//-------
AIStateAttack::AIStateAttack()
{
	type=AI_STATE_ATTACK;
}

void AIStateAttack::enter(Creature* creature)
{
	LOG(creature->objectId,"Entering Attack State");
}

void AIStateAttack::update(Creature* creature)
{
	LOG(creature->objectId,"Updating Attack State");
    
    //update awareness
    creature->processFOV();

    //verify we can still see a target
    if (creature->visibleEnemies.size()>0){
        creature->aiFindTarget();
        //attack state will attack once and return to patrol.
        WORLD.setFiringMode(SNAPSHOT);
        if (creature->hasActionPoints(WORLD.firingCost)){
            WORLD.attack(creature);
            creature->aiFSM.changeState(creature, AI_STATE_PATROL);
        } else {
            creature->endTurn=true;
            LOG(creature->objectId,"No ActionPoints: ending turn");
        }
    } else {
        //no visible enemies so return to Patrol state
        creature->aiFSM.changeState(creature, AI_STATE_PATROL);
        LOG(creature->objectId,"No visibleEnemies: return to Patrol");
    }
}

void AIStateAttack::exit(Creature* creature)
{
	LOG(creature->objectId,"Exiting Attack State");
}


//-------
AIStateRun::AIStateRun()
{
	type=AI_STATE_RUN;
}

void AIStateRun::enter(Creature* creature)
{
	Utility tool;
	type=AI_STATE_RUN;
    moves=tool.findPath(creature->position, creature->destination);
    movesIter = moves.end();
    LOG(creature->objectId, " at "+creature->position.string()+" is running to "+creature->destination.string());
}

void AIStateRun::update(Creature* creature)
{
	LOG(creature->objectId,"Updating Run State");
	Utility tool;
    //update awareness
    creature->processFOV();
    LOG(creature->objectId,"Entering Run State");
    
    //return to Patrol if we've reached safety.
    if (creature->position==creature->destination){
        creature->aiFSM.changeState(creature, AI_STATE_PATROL);
        LOG(creature->objectId,"Reached safety: returning to Patrol");
        return;
    }

    //check we have enough AP for the next move and move towards safety
    movesIter--;
    Position nextPosition=tool.getPositionFromDirection(creature->position, (*movesIter));
	int moveCost=WORLD.map.getMoveCost(nextPosition);
    if (creature->hasActionPoints(moveCost))
    {
		LOG(creature->objectId,"at position "+creature->position.string()+" with AP "+tool.stringFromInt(creature->currentActionPoints)
			+" safety is "+creature->destination.string());
		//if we can't move for whatever reason end the creatures turn. Probably got stuck somewhere.
        //movesIter--;
        bool moved=creature->move((*movesIter));
		if (!moved) {
			creature->endTurn=true;
		}
        LOG(creature->objectId,"moving in direction "+tool.stringFromInt(*movesIter)+" Position is now "+creature->position.string());
    } else {
        //No AP's so end turn. Ensure we increment the movesIter so we pick up
        //the correct move on the next turn.
        movesIter++;
        creature->endTurn=true;
        LOG(creature->objectId,"No ActionPoints: ending turn");
    }
}

void AIStateRun::exit(Creature* creature)
{
	LOG(creature->objectId,"Exiting Run State");
}
